#include "customgraphicsview.h"
#include <QMouseEvent>
#include <QGraphicsRectItem>
#include <QApplication>
#include <QDebug>

/* * * * * * * * * * * * * * * * * * * * * * * * * *
 *                                                 *
 *   Нижеследующий хак во многом базируется на     *
 *   qt/src/gui/graphicsview/qgraphicsview.cpp,    *
 *   но, тем не менее, это не просто копипаст и    *
 *   свободно передирать его нельзя.               *
 *                                                 *
 * * * * * * * * * * * * * * * * * * * * * * * * * */

QHash<QGraphicsItem *, bool> *prevSelState;

CustomGraphicsView::CustomGraphicsView (QObject *parent)
	: rubberbanding(false)
	//, prevSelState(new QHash<QGraphicsItem *, bool>())
{
	prevSelState = new QHash<QGraphicsItem *, bool>();
	ctrlKeyPressed = shiftKeyPressed = false;
}

void CustomGraphicsView::keyPressEvent(QKeyEvent *event)
{
	if (event->modifiers() & Qt::ShiftModifier)
		shiftKeyPressed = true;
	else if (event->modifiers() & Qt::ControlModifier)
		ctrlKeyPressed = true;
}

void CustomGraphicsView::keyReleaseEvent(QKeyEvent *event)
{
	if (!(event->modifiers() & Qt::ShiftModifier))
		shiftKeyPressed = false;
	if (!(event->modifiers() & Qt::ControlModifier))
		ctrlKeyPressed = false;
}

void CustomGraphicsView::mousePressEvent(QMouseEvent *event)
{
	QList<QGraphicsItem *> items = scene()->items();
	prevSelState->clear();
	for(int i=0; i<items.count(); ++i)
		if (items[i]->flags() & QGraphicsItem::ItemIsSelectable)
			(*prevSelState)[items[i]] = items[i]->isSelected();

	QGraphicsView::mousePressEvent(event);

	if (scene()->itemAt(mapToScene(event->pos())))
		return;

	startpos = event->pos();
	rubberbanding = true;

	rubberrect = new QGraphicsRectItem();
	rubberrect->setPen(QPen(Qt::gray));
	rubberrect->setBrush(QColor(255,255,255,120));
	rubberrect->setRect(QRectF());
	if (ctrlKeyPressed || shiftKeyPressed)
	{
		// Выделение было снято методом родителя, напоминаю
		// его теперь нужно обратно выставить (во даже как!)
		for(int i=0; i<items.count(); ++i)
			if (prevSelState->contains(items[i]))
				items[i]->setSelected((*prevSelState)[items[i]]);
	}
	scene()->addItem(rubberrect);

}


void CustomGraphicsView::selectItemsWithShift (QPainterPath &selectionArea)
{
	QList<QGraphicsItem *> items = scene()->items(selectionArea, rubberBandSelectionMode(), Qt::AscendingOrder, viewportTransform());
	QList<QGraphicsItem *> allitems = scene()->items();
	for(int i=0; i<allitems.count(); ++i)
		if (prevSelState->contains(allitems[i]))
			if (items.contains(allitems[i]))
				allitems[i]->setSelected(!(*prevSelState)[allitems[i]]);
			else
				allitems[i]->setSelected((*prevSelState)[allitems[i]]);
}

void CustomGraphicsView::selectItemsWithCtrl (QPainterPath &selectionArea)
{
	QList<QGraphicsItem *> items = scene()->items(selectionArea, rubberBandSelectionMode(), Qt::AscendingOrder, viewportTransform());
	for(int i=0; i<items.count(); ++i)
		items[i]->setSelected(true);
}

void CustomGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
	if (rubberbanding && (!event->buttons() || !rubberrect))
	{
		rubberbanding = false;
		if (rubberrect)
			delete rubberrect;
		rubberrect = NULL;
		return;
	}

	if (rubberbanding)
	{
		if ((startpos-event->pos()).manhattanLength() < QApplication::startDragDistance())
			return;
		QPointF mp = mapToScene(startpos);
		QPointF ep = mapToScene(event->pos());
		rubberrect->setRect(
				(QRectF(qMin(mp.x(), ep.x()),  qMin(mp.y(), ep.y()),
						   qAbs(mp.x()-ep.x())+1, qAbs(mp.y()-ep.y())+1)));
		rubberrect->setVisible(true);

		// Select items
		QPainterPath selectionArea;
		selectionArea.addPolygon(rubberrect->rect());
		selectionArea.closeSubpath();
		if (shiftKeyPressed)
			selectItemsWithShift(selectionArea);
		else if (ctrlKeyPressed)
			selectItemsWithCtrl(selectionArea);
		else if (scene())
			scene()->setSelectionArea(selectionArea, rubberBandSelectionMode(), viewportTransform());
	}
	else QGraphicsView::mouseMoveEvent(event);
}


void CustomGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
	if (rubberrect && rubberbanding)
	{
		scene()->removeItem(rubberrect);
		delete rubberrect;
		rubberrect = NULL;
		rubberbanding = false;
	}

	QGraphicsView::mouseReleaseEvent(event);
}
